package com.sali.utils.loadbalance;

import com.sali.utils.loadbalance.entity.Weight;
import org.springframework.cloud.client.ServiceInstance;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: 平滑加权轮询算法
 * @author: zhang hang
 * @date: 2022/7/18 21:39.
 * @version: 1.0
 */
public class SmoothWeightedRoundRobin implements ILoadBalanceAlgorithm {

    public static final Map<Integer, Integer> STATIC_WEIGHT_MAP = new LinkedHashMap<>();

    static {
        STATIC_WEIGHT_MAP.put(8861, 1);
        STATIC_WEIGHT_MAP.put(8862, 2);
        STATIC_WEIGHT_MAP.put(8863, 3);
        STATIC_WEIGHT_MAP.put(8864, 4);
        STATIC_WEIGHT_MAP.put(8865, 5);
    }

    private static final Map<Integer, Weight> DYNASTIC_WEIGHT_MAP = new LinkedHashMap<>();


    @Override
    public ServiceInstance algorithmDetail(List<ServiceInstance> instances) {

        int totalWeight = 0;
        for (Integer weight : STATIC_WEIGHT_MAP.values()) {
            totalWeight += weight;
        }

        if (DYNASTIC_WEIGHT_MAP.isEmpty()) {
            for (Integer port : STATIC_WEIGHT_MAP.keySet()) {
                Integer weight = STATIC_WEIGHT_MAP.get(port);
                DYNASTIC_WEIGHT_MAP.put(port, new Weight(port, weight, 0));
            }
        }

        // currentWeight += weight
        for (Weight weight : DYNASTIC_WEIGHT_MAP.values()) {
            weight.setCurrentWeight(weight.getCurrentWeight() + weight.getWeight());
        }
        // max(currentWeight)
        Weight maxCurrentWeight = null;
        for (Weight weight : DYNASTIC_WEIGHT_MAP.values()) {
            if (maxCurrentWeight == null || weight.getCurrentWeight() > maxCurrentWeight.getCurrentWeight()) {
                maxCurrentWeight = weight;
            }
        }

        // max(currentWeight) -= sum(weight)
        if ( maxCurrentWeight == null ) {
            return null;
        }
        maxCurrentWeight.setCurrentWeight(maxCurrentWeight.getCurrentWeight() - totalWeight);

        // result
        for (ServiceInstance instance : instances) {
            if (instance.getPort() == maxCurrentWeight.getPort()) {
                return instance;
            }
        }
        return null;
    }
}
